// // Copyright (c) 2009 All Right Reserved // // vl // // 2009-01-01 // Contains ... using System; using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Globalization; using System.Linq; using System.Text; using System.Xml.Linq; using JetBrains.Annotations; using LargoCommon.Abstract; using LargoCommon.Composer; using LargoCommon.Interfaces; using LargoCommon.Localization; using LargoCommon.Midi; namespace LargoCommon.Music { /// /// Musical file. /// [Serializable] public sealed class MusicalBlock : MusicalContent { #region Fields /// /// Musical file. /// private MusicalBundle musicalBundle; /// /// Block tracks. /// [NonSerialized] private MusicalStrip strip; #endregion #region Constructors /// /// Initializes a new instance of the MusicalBlock class. /// public MusicalBlock() : base() { var context = new MusicalContext(MusicalSettings.Singleton, this.Header); this.Body = new MusicalBody(context); this.Strip = new MusicalStrip(context); this.ContainsMusic = false; this.FileHeading = new FileHeading(); } /// /// Initializes a new instance of the class. /// /// The given header. public MusicalBlock(MusicalHeader givenHeader) { //// this.BlockMidi = new MusicalBlockMidi(); this.Header = givenHeader; var context = new MusicalContext(MusicalSettings.Singleton, this.Header); this.Body = new MusicalBody(context); this.Strip = new MusicalStrip(context); this.ContainsMusic = false; this.FileHeading = new FileHeading(); } /// /// Initializes a new instance of the class. /// /// The mark block. public MusicalBlock(XElement markBlock) { Contract.Requires(markBlock != null); if (markBlock == null) { return; } var xheader = markBlock.Element("Header"); this.Header = new MusicalHeader(xheader); this.Name = (string)markBlock.Attribute("Name"); var context = new MusicalContext(MusicalSettings.Singleton, this.Header); XElement xbody = markBlock.Element("Body"); if (xbody == null) { return; } var xstrip = markBlock.Element("Strip"); if (xstrip == null) { return; } this.Strip = new MusicalStrip(xstrip, context); this.ContainsMusic = true; //// var xbody = markBlock.Element("Body"); //// block.Body = MusicalBodyPort.ReadMusicalBody(xbody, context); //// this.Body = new MusicalBody(context); this.ConvertStripToBody(true); //// 2019/1 var setup = context.Settings; //// 2019/12 condition is necessary - this.Body.SetHarmonicStatusFromTones(3, setup.FullHarmonization); var xelements = xbody.Elements(); foreach (XElement xbar in xelements) { var barNumber = (int)xbar.Attribute("Number"); MusicalBar bar = this.Body.GetBar(barNumber); var tempo = (int)xbar.Attribute("Tempo"); bar.TempoNumber = tempo; var xharmony = xbar.Element("Harmony"); var harmonicBar = new HarmonicBar(this.Header, xharmony) { BarNumber = barNumber }; bar.HarmonicBar = harmonicBar; } this.LoadFirstStatusToLines(); //// 2019/10 this.FileHeading = new FileHeading(); } #endregion #region Properties - Xml /// Gets Xml representation. /// Property description. public XElement GetXElement { get { XElement xblock = new XElement( "Block", new XAttribute("Number", this.Header.Number), new XAttribute("FileName", this.Header.FileName ?? string.Empty), new XAttribute("Name", this.Header.Name ?? string.Empty)); XElement xheader = this.Header.GetXElement; xblock.Add(xheader); XElement xbody = new XElement("Body"); foreach (var bar in this.Body.Bars) { if (bar?.HarmonicBar == null) { continue; } var xbar = new XElement("Bar"); xbar.Add(new XAttribute("Number", bar.BarNumber)); var xtempo = new XAttribute("Tempo", bar.TempoNumber); xbar.Add(xtempo); var xharmony = bar.HarmonicBar.GetXElement; xbar.Add(xharmony); xbody.Add(xbar); } xblock.Add(xbody); //// Prepare list for usage by MusicalLine.GetXElement, //// status will be written as lists of bars to tracks. if (!this.IsStripStatusOk) { this.ConvertBodyStatusToStrip(); } XElement xstrip = this.Strip.GetXElement; xblock.Add(xstrip); return xblock; } } #endregion #region Properties /// /// Gets or sets the file heading. /// /// /// The file heading. /// public FileHeading FileHeading { get; set; } /// /// Gets or sets the musical file. /// /// /// The musical file. /// public MusicalBundle MusicalBundle { get => this.musicalBundle; set => this.musicalBundle = value; } /// /// Gets or sets the body. /// /// /// The body. /// public MusicalBody Body { get; set; } /// /// Gets or sets the block tracks. /// /// /// The block tracks. /// public MusicalStrip Strip { get { Contract.Ensures(Contract.Result() != null); if (this.strip == null) { throw new InvalidOperationException("Strip is null."); } return this.strip; } set => this.strip = value ?? throw new ArgumentException(LocalizedMusic.String("Argument cannot be null."), nameof(value)); } /// Gets or sets a value indicating whether this object is body status ok. /// True if this object is body status ok, false if not. [UsedImplicitly] public bool IsBodyStatusOk { get; set; } /// /// Gets or sets a value indicating whether this object is strip status ok. /// /// True if this object is strip status ok, false if not. public bool IsStripStatusOk { get; set; } /// /// Gets or sets a value indicating whether Is Selected. /// /// Property description. [UsedImplicitly] public bool IsSelected { get; set; } /// /// Gets Musical Identification. /// /// Property description. public IList Identification { get { var items = new List(); var item = new KeyValuePair(LocalizedMusic.String("Number of bars"), this.Header.NumberOfBars.ToString(CultureInfo.InvariantCulture)); items.Add(item); item = new KeyValuePair(LocalizedMusic.String("Number of lines"), this.Strip.Lines.Count.ToString(CultureInfo.InvariantCulture)); items.Add(item); item = new KeyValuePair(LocalizedMusic.String("Harmonic order"), this.Header.System.HarmonicOrder.ToString(CultureInfo.InvariantCulture)); items.Add(item); item = new KeyValuePair(LocalizedMusic.String("Rhythmic order"), this.Header.System.RhythmicOrder.ToString(CultureInfo.InvariantCulture)); items.Add(item); item = new KeyValuePair(LocalizedMusic.String("Metric"), string.Format(CultureInfo.InvariantCulture, "{0}/{1}", this.Header.Metric.MetricBeat, this.Header.Metric.MetricGround)); items.Add(item); var musicalTempo = RhythmicSystem.ApproximateMusicalTempo(this.Header.Tempo); item = new KeyValuePair(LocalizedMusic.String("Tempo"), string.Format(CultureInfo.InvariantCulture, "{0}({1})", this.Header.Tempo, LocalizedMusic.String("Tempo" + ((byte)musicalTempo)))); items.Add(item); //// item = new KeyValuePair("Original file name", this.FileName); //// items.Add(item); item = new KeyValuePair(LocalizedMusic.String("Original division"), this.Header.Division.ToString(CultureInfo.InvariantCulture)); items.Add(item); return items; } } /// /// Gets the identification string. /// /// /// The identification string. /// public string IdentificationString { get { StringBuilder sb = new StringBuilder(); var idents = this.Identification; foreach (var ident in idents) { sb.AppendFormat("{0}: {1}\n", ident.Key, ident.Value); } return sb.ToString(); } } #endregion /// Gets or sets the lines. /// The lines. public override List ContentLines { get { var ilines = (from line in this.Strip.Lines select line as IAbstractLine).ToList(); return ilines; } } /// Gets or sets the harmony. /// The harmony. public override List ContentBars { get { var ibars = (from bar in this.Body.Bars select bar as IAbstractBar).ToList(); return ibars; } } /// /// Gets the content elements. /// /// /// The content elements. /// public new IList ContentElements { get { var elements = this.Body.AllElements.ToList(); return elements; } } #region Pattern - properties /// /// Gets the melodic patterns. /// /// /// The melodic patterns. /// public IList MelodicPatterns { get { var body = this.Body; var list = new List(); foreach (var bar in body.Bars) { var pattern = new MelodicPattern(this.Header, bar) { SetName = this.FullName }; if (!pattern.IsEmpty && !pattern.ExistsInPatterns(list)) { list.Add(pattern); } } return list; } } /// /// Gets the rhythmic patterns. /// /// /// The rhythmic patterns. /// public IList RhythmicPatterns { get { var body = this.Body; var list = new List(); foreach (var bar in body.Bars) { var pattern = new RhythmicPattern(this.Header, bar) { SetName = this.FullName }; if (!pattern.IsEmpty && !pattern.ExistsInPatterns(list)) { list.Add(pattern); } } return list; } } #endregion #region Other properties /// Gets string with bar details. /// General musical property. /// Returns value. [UsedImplicitly] public string BarDetailsToString { get { var s = new StringBuilder(); s.Append(" Bar details \n"); s.Append("------------------------------------------------------\n"); var bars = from b in this.Body.Bars orderby b.BarNumber select b; var musicTracks = (from p in this.Strip.Lines orderby p.LineIndex descending select p).ToList(); foreach (var bar in bars.Where(bar => bar != null && !bar.IsEmpty)) { s.AppendFormat(CultureInfo.CurrentCulture, "* Bar {0,2}: *\r\n", bar.BarNumber); foreach (var mtrack in musicTracks.Where(mtrack => mtrack?.Tones != null && !mtrack.IsEmpty)) { s.AppendFormat(CultureInfo.CurrentCulture, "Part {0,2}: ", mtrack.LineIndex); var tones = mtrack.MusicalTonesInBar(bar.BarNumber); foreach (var mt in tones.Where(mt => mt != null)) { s.Append(mt); } s.AppendLine(string.Empty); } s.AppendLine(string.Empty); } return s.ToString(); } } #endregion #region Static factory /// /// Imports Midi File. /// /// The midi block. /// The harmonic order. /// The rhythmic order. /// Returns value. public static MusicalBlock NewMusicalBlock(MidiBlock midiBlock, byte harmonicOrder, byte rhythmicOrder) { Contract.Requires(midiBlock != null); Contract.Requires(midiBlock.Area != null); Contract.Requires(midiBlock.Sequence != null); if (midiBlock.Header.Clone() is MusicalHeader musicHeader) { musicHeader.System.HarmonicOrder = harmonicOrder; musicHeader.System.RhythmicOrder = rhythmicOrder; var musicalBlock = new MusicalBlock { //// Number = midiBlock.Number, //// BlockMidi = { OriginalBarFrom = midiBlock.Area.BarFrom, OriginalBarTo = midiBlock.Area.BarTo, //// OriginalTimeFrom = midiBlock.MidiTimeFrom, OriginalTimeTo = midiBlock.MidiTimeTo }, Header = musicHeader }; var context = new MusicalContext(MusicalSettings.Singleton, musicalBlock.Header); musicalBlock.Body = new MusicalBody(context); //// 2019/02 again used!? musicalBlock.Strip = new MusicalStrip(context); var header = musicalBlock.Header; foreach (var midiTrack in midiBlock.Sequence) { var mtrack = (MidiTrack)midiTrack; mtrack.Metric = header.Metric; mtrack.BarDivision = MusicalProperties.BarDivision(header.Division, header.Metric.MetricBeat, header.Metric.MetricGround); //// both delta and total is needed //// midiTrack.Sequence.RecomputeAbsoluteTimes(); } //// this.Strip.Lines = new List(); musicalBlock.Strip.ResetLines(); //// midiBlock.Area.BarFrom, midiBlock.Area.BarTo, midiBlock.MidiTimeFrom, midiBlock.MidiTimeTo musicalBlock.AppendMidiTracks(midiBlock); //// this.MusicalBlock.Division = midiTracks.Division; var cmt = (byte)(from t in midiBlock.Sequence where t.IsMelodic select 1).Count(); var crt = (byte)(from t in midiBlock.Sequence where t.IsRhythmical select 1).Count(); musicalBlock.Header.NumberOfMelodicLines = cmt; musicalBlock.Header.NumberOfRhythmicLines = crt; musicalBlock.Header.NumberOfLines = cmt + crt; return musicalBlock; } return null; } /// /// Prepares the block. /// /// The given number of bars. /// The given strip prototype. /// /// Returns value. /// [UsedImplicitly] public static MusicalBlock PrepareBlock(int givenNumberOfBars, PackStrip givenStripPrototype) { var header = MusicalHeader.GetDefaultMusicalHeader; header.NumberOfBars = givenNumberOfBars; header.Name = "Test"; header.FileName = "Test-File"; //// header.System.RhythmicOrder = firstHarBar.RhythmicStructure.Order; var context = new MusicalContext(MusicalSettings.Singleton, header); var strip = new MusicalStrip(context); foreach (var prototype in givenStripPrototype.PackLines) { var channel = MusicalProperties.ChannelForPartNumber(prototype.LineIndex); var status = new LineStatus( 1, prototype.Status.LineType, prototype.Status.Instrument, LinePurpose.Composed, channel); //// firstStatus.MelodicVariety = null; //// 2018/09 new MusicalVariety(MusicalSettings.Singleton); var newTrack = new MusicalLine(status) { FirstStatus = { LocalPurpose = LinePurpose.Composed } }; strip.AddLine(newTrack, true); } var block = new MusicalBlock { Header = header, Strip = strip }; block.Header.Number = 1; //// 2018/10 block.ConvertStripToBody(true); return block; } /// /// Defaults the block. /// /// Returns value. public static MusicalBlock DefaultBlock() { var block = new MusicalBlock(); var lineStatus = new LineStatus() { LineType = MusicalLineType.Melodic, Instrument = new MusicalInstrument(MidiMelodicInstrument.StringEnsemble1), Octave = MusicalOctave.TwoLine, Loudness = MusicalLoudness.MeanLoudness, MelodicFunction = MelodicFunction.HarmonicMotion, MelodicShape = MelodicShape.Scales }; block.AddContentBar(1, null); var newline = block.AddContentLine(lineStatus); var voice = new MusicalVoice { Instrument = new MusicalInstrument(MidiMelodicInstrument.StringEnsemble1), Octave = MusicalOctave.OneLine, Loudness = MusicalLoudness.MeanLoudness, Line = newline }; newline.Voices = new List { voice }; newline.MainVoice = voice; //// var bar = block.AddContentBar(1, null); //// Convert current body back to strip!?! (Status is in elements) block.ConvertBodyToStrip(false, false); block.Header.NumberOfLines = block.ContentLines.Count; block.Header.NumberOfMelodicLines = (byte)block.Header.NumberOfLines; block.Header.NumberOfRhythmicLines = 0; block.Header.NumberOfBars = block.ContentBars.Count; return block; } #endregion #region Add content /// /// Adds the content bar. /// /// The bar number. /// The last bar. /// Returns musical bar. public IAbstractBar AddContentBar(int barNumber, MusicalBar lastBar) { var bar = new MusicalBar(barNumber++, this.Body); var chord = new HarmonicStructure(this.Header.System.HarmonicSystem, "0,4,7"); bar.HarmonicBar.SetStructure(chord); this.Body.Bars.Add(bar); this.Header.NumberOfBars = this.Body.Bars.Count; MusicalElement lastElement = null; LineStatus status = null; foreach (var line in this.Strip.Lines) { if (lastElement == null && lastBar != null) { lastElement = lastBar.GetElement(line.LineIdent); } var musicalLine = line as MusicalLine; if (lastElement != null) { status = (LineStatus)lastElement.Status.Clone(); } else { status = (LineStatus)musicalLine.FirstStatus.Clone(); } var element = new MusicalElement(status, lastElement) { Bar = bar, Line = line }; bar.Elements.Add(element); lastElement = element; } return bar; } /// /// Adds the line. /// /// The given line status. /// Returns value. public override IAbstractLine AddContentLine(LineStatus givenStatus) { var lines = (List)this.Strip.Lines; var lineIndex = this.Header.NumberOfLines; //// tracks.Count() + 1; var newLine = new MusicalLine(givenStatus) { LineIndex = lineIndex, Purpose = LinePurpose.Composed }; if (givenStatus.LineType == MusicalLineType.Melodic) { var channel = this.Strip.FindFreeChannel(newLine.LineIndex); newLine.MainVoice.Channel = channel; } else { newLine.MainVoice.Channel = MidiChannel.DrumChannel; } lines.Add(newLine); //// Model have to be assigned before loading this.AddElementsForLine(newLine); this.Header.NumberOfLines = lines.Count; this.Strip.Context.Header.NumberOfLines = this.Header.NumberOfLines; //// ? return newLine; } /// /// Adds the line. /// /// The given line. public void AddLine(MusicalLine givenLine) { var lines = (List)this.Strip.Lines; //// var lineIndex = this.Header.NumberOfLines; //// tracks.Count() + 1; this.Header.NumberOfLines++; lines.Add(givenLine); //// Model have to be assigned before loading this.Header.NumberOfLines = this.ContentLines.Count; this.AddElementsForLine(givenLine); } /// /// Loads the instruments to tracks. /// public void LoadFirstStatusToLines() { foreach (var line in this.Strip.Lines) { foreach (var bar in this.Body.Bars) { var point = new MusicalPoint(line.LineIndex, bar.BarNumber); var element = this.Body.GetElement(point); if (element?.Status?.Instrument != null && !element.Status.Instrument.IsEmpty) { line.FirstStatus.Instrument = element.Status.Instrument; //// FixedInstrument line.CurrentInstrument = line.FirstStatus.Instrument.Number; //// FixedInstrument line.FirstStatus.LineType = element.Status.LineType; //// line.FirstStatus.Instrument = new MusicalInstrument(element.Status.InstrumentNumber, element.Status.LineType); break; } } line.FirstStatus.MelodicVariety = new MusicalVariety(MusicalSettings.Singleton); } } /// /// Clones the specified include tones. /// /// If set to true [clone tracks]. /// If set to true [include tones]. /// /// Returns value. /// public MusicalBlock Clone(bool cloneTracks, bool includeTones) { var block = (MusicalBlock)this.Clone(); //// block.Strip.SetTracks(new List()); if (!cloneTracks) { return block; } block.strip = this.Strip.Clone(includeTones); return block; } /// /// Gets the harmonic stream. /// /// The given maximum tones in chord. /// if set to true [given full harmonization]. /// Returns value. [UsedImplicitly] public HarmonicStream GetHarmonicStream(byte givenMaxTonesInChord, bool givenFullHarmonization) { this.Body.SetHarmonicStatusFromTones(givenMaxTonesInChord, givenFullHarmonization); var harmonicStream = new HarmonicStream(this.Body.Context.Header); //// this.Name, "Derived from block" foreach (MusicalBar bar in this.Body.Bars) { var harBar = bar.HarmonicBar; harmonicStream.HarmonicBars.Add(harBar); } return harmonicStream; } /// /// Sets the tempo events. /// /// The given tempo changes. [UsedImplicitly] public void SetTempoEvents(IEnumerable givenTempoChanges) { Contract.Requires(givenTempoChanges != null); var list = new List(); var barDivision = MusicalProperties.BarDivision(this.Header.Division, this.Header.Metric.MetricBeat, this.Header.Metric.MetricGround); var barDuration = MusicalProperties.MidiDuration(this.Header.System.RhythmicOrder, this.Header.System.RhythmicOrder, barDivision); // ReSharper disable once LoopCanBePartlyConvertedToQuery foreach (var change in givenTempoChanges) { var barDeltaTime = barDuration * (change.BarNumber - 1); var ev = new MetaTempo(0, 100) { StartTime = barDeltaTime, Tempo = change.TempoNumber }; //// 100 is arbitrary number here //// Tempo have to change just before start of bar list.Add(ev); } this.Body.TempoEvents = list; } /// /// Deletes the line. /// /// Index of the line. public void DeleteLine(int lineIndex) { this.Body.DeleteLine(lineIndex); this.Strip.DeleteLine(lineIndex); this.Header.NumberOfLines--; } /// /// Deletes the line. /// /// The line identifier. public void DeleteLine(Guid lineIdent) { this.Body.DeleteLine(lineIdent); this.Strip.DeleteLine(lineIdent); this.Header.NumberOfLines--; /* var tracks = this.Strip.Lines; var lineIndex = (from line in tracks where line.LineIdent == lineIdent select line.LineIndex).FirstOrDefault(); if (lineIndex < tracks.Count && tracks[lineIndex].LineIdent == lineIdent) { this.DeleteLine(lineIndex); } */ } /// /// Append CompactMidiStrip. /// /// The midi block. public void AppendMidiTracks(MidiBlock midiBlock) /* CompactMidiStrip midiTracks int barNumberFrom, int barNumberTo, long timeFrom, long timeTo */ { if (midiBlock.Sequence == null) { return; } var lineIndex = this.Strip.Lines.Count; this.Header.NumberOfBars = midiBlock.Area.BarTo - midiBlock.Area.BarFrom + 1; var orderedToneTracks = (from mt in midiBlock.Sequence orderby mt.Octave where mt.Sequence != null select mt).ToList(); //// 2019/02 this.Body.SetTempoEventsFrom(midiBlock.MidiTimeFrom, midiBlock.MidiTimeTo, orderedToneTracks); //// midiTrack.Sequence.RecomputeDeltaTimes(); orderedToneTracks.ForEach(midiTrack => this.AppendMidiTrack(midiTrack, lineIndex++)); //// determineBarNumbers } /// /// Appends the midi line. /// /// The midi line. /// The line number. public void AppendMidiTrack(IMidiTrack midiTrack, int lineIndex) /* 2019/01 MusicalSection givenArea, */ { //// ref int lineIndex, bool determineBarNumbers Contract.Requires(midiTrack != null); var line = new MusicalLine(midiTrack, this.Strip) /* 2019/01 givenArea, */ { LineIndex = lineIndex }; var tracks = (List)this.Strip.Lines; tracks.Add(line); //// Model have to be assigned before loading } #endregion #region Analysis - Public /// /// Analyzes the tempo changes. /// /// Returns value. public IEnumerable AnalyzeTempoChanges() { var changes = new List(); int lastTempoNumber = 0; foreach (var bar in this.Body.Bars) { /* var status = bar.Status; if (status == null) { continue; } */ if (bar.TempoNumber != lastTempoNumber) { var tc = new TempoChange(bar.BarNumber) { TempoNumber = bar.TempoNumber }; changes.Add(tc); } lastTempoNumber = bar.TempoNumber; } return changes; } #endregion #region String representation /// String representation of the object. /// Returns value. public override string ToString() { //// if (this.Name == null) { return string.Empty; } var s = new StringBuilder(); s.Append("\t" + this.Header.Name.ToString(CultureInfo.CurrentCulture)); return s.ToString(); } #endregion #region Body-Strip Status Conversion -- see also Strip.WriteBody /// /// Gets the line status list. /// This methods probably do not work properly !?!? /// Now used before composition in combination with SendStatusToTones!? /// public void ConvertStripStatusToBody() { if (this.Body?.Bars == null) { return; } foreach (MusicalLine line in this.Strip.Lines.Where(mtrack => mtrack != null)) { line.CurrentStatus = line.FirstStatus; foreach (var bar in this.Body.Bars) { var element = (from elem in bar.Elements where elem.Line.LineIdent == line.LineIdent select elem) .FirstOrDefault(); if (element == null) { continue; } //// Status from tones only in case where there is no status defined in tracks if (line.StatusList != null && line.StatusList.Any()) { var status = (from ts in line.StatusList where ts.BarNumber == bar.BarNumber select ts).FirstOrDefault(); if (status != null) { //// 2018/10 && trackStatus.Purpose != LinePurpose.None !? line.CurrentStatus = status; } var newStatus = (LineStatus)line.CurrentStatus.Clone(); newStatus.BarNumber = bar.BarNumber; element.Status = newStatus; //// !!!! otherwise there are 2 different statuses for one element ...?? } else { element.SetElementStatusFromTones(); } } } } /// /// Sets the line status list i.e. list of bar status in each given line. /// public void ConvertBodyStatusToStrip() { foreach (MusicalLine line in this.Strip.Lines.Where(mtrack => mtrack != null)) { line.StatusList = new List(); } foreach (var bar in this.Body.Bars) { foreach (var element in bar.Elements) { var line = element.MusicalLine; line.StatusList?.Add(element.Status); } } } #endregion #region Strip-Body conversion /// /// Converts the strip to body. /// /// if set to true [keep status]. public void ConvertStripToBody(bool keepStatus) { /* 2019/02 if (this.Body == null) { this.Body = new MusicalBody(this.Strip.Context); } //// !?!?!? TempoEvents = this.Body.TempoEvents //// to keep tempo-events var tempoEvents = this.Body.TempoEvents; */ //// Keep original status (tempo, harmony) !? var newBody = new MusicalBody(this.Strip); //// 2019/10 - added missing if !!?!?!?!!!!!!! //// if (keepStatus) { if (this.Body != null) { foreach (var bar in this.Body.Bars) { var newBar = newBody.GetBar(bar.BarNumber); if (newBar != null) { newBar.TempoNumber = bar.TempoNumber; newBar.HarmonicBar = (HarmonicBar)bar.HarmonicBar.Clone(); //// newBar.Status = bar.Status; } } } //// } this.Body = newBody; this.ConvertStripStatusToBody(); //// 2019/10 !!!!!!! /* 2019/02 var h = this.Header; var barMidiDuration = MusicalProperties.BarMidiDuration(h.System.RhythmicOrder, h.Metric.MetricBeat, h.Metric.MetricGround, h.Division); if (tempoEvents != null) { var midiEvents = tempoEvents as IList ?? tempoEvents.ToList(); if (midiEvents.Any()) { int currentTempoNumber = 0; foreach (var bar in this.Body.Bars) { //// tev.BarNumber == bar.BarNumber ? if ((from tev in midiEvents where tev.StartTime <= bar.TimePoint && bar.TimePoint <= tev.StartTime + barMidiDuration select tev).FirstOrDefault() is MidiEvents.MetaTempo metaTempo) { currentTempoNumber = metaTempo.Tempo; } bar.Status.TempoNumber = currentTempoNumber; } } } */ this.Header.NumberOfLines = this.Strip.Lines.Count; this.Strip.Context.Header.NumberOfLines = this.Header.NumberOfLines; //// Tones are directed by status!?? - When opening a mif-file?! - Temporary!? if (keepStatus) { this.ConvertStripStatusToBody(); } } /// /// Converts the body to strip. /// /// if set to true [check tones]. /// if set to true [including status]. public void ConvertBodyToStrip(bool checkTones, bool includingStatus) { this.Strip.ResetTones(); this.Strip.WriteBody(this.Body); if (checkTones) { this.Strip.CorrectOctaves(); } if (includingStatus) { this.ConvertBodyStatusToStrip(); } } #endregion #region Private methods /// Makes a deep copy of the MusicalBlock object. /// Returns object. private object Clone() { var header = (MusicalHeader)this.Header.Clone(); var block = new MusicalBlock { Header = header //// Number = this.Header.Number }; //// block.Strip.Lines = new Collection(); //// foreach (MusicalLine newTrack in this.MusicalTracks.Select(line => (MusicalLine)line.Clone())) //// { block.Strip.Lines.Add(newTrack); } return block; } #endregion } }